<template>
    <MyArticle class="readingNotes-webgl-07" title="WebGL学习笔记之七：光照" date="2021年05月25日">
        <div class="_article-content">
            <p>讲述如何在三维场景中实现不同类型的光照以及其产生的效果。包括点光源光、平行光、环境光、漫反射以及环境反射等内容。</p>
            <p>术语“着色”的真正含义就是，根据光照条件重建物体各表面明暗不一的效果的过程。</p>
            <h3 class="title">光源类型与反射光</h3>
            <p><strong>平行光</strong>：光线是相互平行的，平行光具有方向。平行光可以看作是无限远处的光源发出的光，可以用一个方向和一个颜色来定义。</p>
            <p><strong>点光源光</strong>：从一个点向周围的所有的方向发出的光。光线的方向将根据点光源的位置和被照射之处的位置计算出来。</p>
            <p><strong>环境光</strong>：指那些经光源（点光源或者平行光源）发出后，被墙壁等物体多次反射，然后照射到物体表面上的光。环境光从各个角度照射物体，其强度都是一致的。环境光不需要指定位置和方向，只需要指定颜色即可。</p>
            <p>物体反射光取决于两个因素：<strong>入射光和物体表面的类型</strong>，入射光包括光的方向和颜色，物体表面的信息包括表面的固有颜色和反射特性。</p>
            <p>物体表面反射光线的方式有两种：<strong>漫反射（diffuse reflection）</strong>、<strong>环境反射（environemnt reflection）</strong>。</p>
            <p>在漫反射中，反射光的颜色取决于入射光的颜色、表面的基底色、入射光与表面形成的入射角。<strong>入射角是入射光与表面的法线形成的夹角，用θ表示。</strong>漫反射的光颜色通过下列公式计算得到：</p>
            <pre><code>漫反射光颜色 = 入射光颜色 * 表面基底色 * cosθ</code></pre>
            <p>在环境反射中，反射光的方向可以认为就是入射光的反方向。由于环境光照射物体的方式就是各方向均匀、强度相等的，所以反射光也是均匀的：</p>
            <pre><code>环境反射光颜色 = 入射光颜色 * 表面基底色</code></pre>
            <p>当漫反射与环境反射同时存在时，物体最终的反射光颜色是两者之和：</p>
            <pre><code>表面的反射光颜色 = 漫反射光颜色 + 环境反射光颜色</code></pre>
            <h3 class="title">平行光下的漫反射</h3>
            <p>入射角的余弦值可以通过下列公式计算出来：</p>
            <pre><code>cosθ = 光线方向 * 法线方向</code></pre>
            <p><strong>光线方向其实是入射方向的反方向，即从入射点指向光源方向。</strong>光线方向矢量和法线方向矢量的长度必须为1。将一个矢量的长度调整为1，可以使用GLSL ES内置的归一化函数。从而漫反射光的颜色计算式子变为：</p>
            <pre><code>漫反射光颜色 = 入射光颜色 * 表面基底色 * (光线方向 * 法线方向)</code></pre>
            <p><strong>法线，即物体表面的朝向，即垂直于表面的方向</strong>。物体表面的正面和背面取决于绘制表面时的顶点顺序。正表面的绘制顶点顺序是顺时针的。一个平面只有一个法向量。</p>
            <p>无光照情况下的效果：</p>
            <canvas ref="canvasRef1" v-show="!img1" class="webgl-canvas"></canvas>
            <img :src="img1" v-show="img1" class="webgl-canvas"/>
            <p>添加以下平行光之后的效果：</p>
            <pre><code>const lightColor = [1.0, 1.0, 1.0]
const lightDirection = new Vector3([0.5, 3.0, 4.0])</code></pre>
            <canvas ref="canvasRef0" v-show="!img0" class="webgl-canvas"></canvas>
            <img :src="img0" v-show="img0" class="webgl-canvas"/>
            <pre><code>// 顶点着色器
const VSHADER_SOURCE = `
    attribute vec4 a_Position;
    attribute vec4 a_Color;
    attribute vec4 a_Normal; // 法向量
    uniform mat4 u_Matrix;
    uniform vec3 u_LightColor; // 光线颜色
    uniform vec3 u_LightDirection; // 光线方向，归一化的世界坐标
    varying vec4 v_Color;
    void main() {
        gl_Position = u_Matrix * a_Position;
        vec3 normal = normalize(vec3(a_Normal));
        float nDotL = max(dot(u_LightDirection, normal), 0.0); // 如果入射角大于90度，则表明光线照射在背面
        vec3 diffuse = u_LightColor * vec3(a_Color) * nDotL;
        v_Color = vec4(diffuse, a_Color.a);
    }
`
......
const eleSize = datas.BYTES_PER_ELEMENT

const aPosition = gl.getAttribLocation(gl.program, 'a_Position')
gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, 9 * eleSize, 0)
gl.enableVertexAttribArray(aPosition)

const aColor = gl.getAttribLocation(gl.program, 'a_Color')
gl.vertexAttribPointer(aColor, 3, gl.FLOAT, false, 9 * eleSize, 3 * eleSize)
gl.enableVertexAttribArray(aColor)

const aNormal = gl.getAttribLocation(gl.program, 'a_Normal')
gl.vertexAttribPointer(aNormal, 3, gl.FLOAT, false, 9 * eleSize, 6 * eleSize)
gl.enableVertexAttribArray(aNormal)

// 顶点数据定义如下：
const datas = new Float32Array([
    1.0, 1.0, 1.0, 0.4, 0.4, 1.0, 0.0, 0.0, 1.0, // front
    -1.0, 1.0, 1.0, 0.4, 0.4, 1.0, 0.0, 0.0, 1.0,
    -1.0, -1.0, 1.0, 0.4, 0.4, 1.0, 0.0, 0.0, 1.0,
    1.0, -1.0, 1.0, 0.4, 0.4, 1.0, 0.0, 0.0, 1.0,

    1.0, 1.0, 1.0, 0.4, 1.0, 0.4, 1.0, 0.0, 0.0, // right
    1.0, -1.0, 1.0, 0.4, 1.0, 0.4, 1.0, 0.0, 0.0,
    1.0, -1.0, -1.0, 0.4, 1.0, 0.4, 1.0, 0.0, 0.0,
    1.0, 1.0, -1.0, 0.4, 1.0, 0.4, 1.0, 0.0, 0.0,

    1.0, 1.0, 1.0, 1.0, 0.4, 0.4, 0.0, 1.0, 0.0, // up
    1.0, 1.0, -1.0, 1.0, 0.4, 0.4, 0.0, 1.0, 0.0,
    -1.0, 1.0, -1.0, 1.0, 0.4, 0.4, 0.0, 1.0, 0.0,
    -1.0, 1.0, 1.0, 1.0, 0.4, 0.4, 0.0, 1.0, 0.0,

    -1.0, 1.0, 1.0, 1.0, 1.0, 0.4, -1.0, 0.0, 0.0, // left
    -1.0, 1.0, -1.0, 1.0, 1.0, 0.4, -1.0, 0.0, 0.0,
    -1.0, -1.0, -1.0, 1.0, 1.0, 0.4, -1.0, 0.0, 0.0,
    -1.0, -1.0, 1.0, 1.0, 1.0, 0.4, -1.0, 0.0, 0.0,

    -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 0.0, -1.0, 0.0, // down
    1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 0.0, -1.0, 0.0,
    1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 0.0, -1.0, 0.0,
    -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 0.0, -1.0, 0.0,

    1.0, -1.0, -1.0, 0.4, 1.0, 1.0, 0.0, 0.0, -1.0, // back
    -1.0, -1.0, -1.0, 0.4, 1.0, 1.0, 0.0, 0.0, -1.0,
    -1.0, 1.0, -1.0, 0.4, 1.0, 1.0, 0.0, 0.0, -1.0,
    1.0, 1.0, -1.0, 0.4, 1.0, 1.0, 0.0, 0.0, -1.0
])
const indices = new Uint8Array([
    0, 1, 2, 0, 2, 3,
    4, 5, 6, 4, 6, 7,
    8, 9, 10, 8, 10, 11,
    12, 13, 14, 12, 14, 15,
    16, 17, 18, 16, 18, 19,
    20, 21, 22, 20, 22, 23
])</code></pre>
            <h3 class="title">环境光下的漫反射</h3>
            <p>上述立方体的右侧面几乎是全黑的，原因是缺少环境光。增加环境光之后，效果更逼真：</p>
            <pre><code>const ambientLight = [0.2, 0.2, 0.2]</code></pre>
            <canvas ref="canvasRef2" v-show="!img2" class="webgl-canvas"></canvas>
            <img :src="img2" v-show="img2" class="webgl-canvas"/>
            <pre><code>// 顶点着色器
const VSHADER_SOURCE = `
    attribute vec4 a_Position;
    attribute vec4 a_Color;
    attribute vec4 a_Normal;
    uniform mat4 u_Matrix;
    uniform vec3 u_LightColor;
    uniform vec3 u_LightDirection;
    uniform vec3 u_AmbientLight;
    varying vec4 v_Color;
    void main() {
        gl_Position = u_Matrix * a_Position;
        vec3 normal = normalize(vec3(a_Normal));
        float nDotL = max(dot(u_LightDirection, normal), 0.0);
        vec3 diffuse = u_LightColor * vec3(a_Color) * nDotL;
        vec3 ambient = u_AmbientLight * a_Color.rgb; // 计算环境光的反射
        v_Color = vec4(diffuse + ambient, a_Color.a);
    }
`
......
// 设置环境光颜色
const uAmbientLightColor = gl.getUniformLocation(gl.program, 'u_AmbientLight')
gl.uniform3f(uAmbientLightColor, ...ambientLight)</code></pre>
            <h3 class="title">运动物体的光照效果</h3>
            <p>可以通过将变换之前的法向量乘以模型矩阵的<strong>逆转置矩阵</strong>，即逆矩阵的转置。</p>
            <p>如果矩阵M的逆矩阵是R，那么R*M或者M*R的结果为单位矩阵。转置则是将矩阵的行列进行调换。Matrix4对象有以下方法求逆转置矩阵：</p>
            <pre><code>Matrix4.setInverseOf(m) // 使自身成为矩阵m的逆矩阵
Matrix4.transpose() // 对自身进行转置操作，并将自身设置为转置之后的结果</code></pre>
            <canvas ref="canvasRef3" v-show="!img3" class="webgl-canvas"></canvas>
            <img :src="img3" v-show="img3" class="webgl-canvas"/>
            <pre><code>// 顶点着色器
const VSHADER_SOURCE = `
    attribute vec4 a_Position;
    attribute vec4 a_Color;
    attribute vec4 a_Normal;
    uniform mat4 u_Matrix;
    uniform mat4 u_NormalMatrix; // 逆转置矩阵
    uniform vec3 u_LightColor;
    uniform vec3 u_LightDirection;
    uniform vec3 u_AmbientLight;
    varying vec4 v_Color;
    void main() {
        gl_Position = u_Matrix * a_Position;
        vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal)); // 计算变换之后的法向量并归一化
        float nDotL = max(dot(u_LightDirection, normal), 0.0);
        vec3 diffuse = u_LightColor * vec3(a_Color) * nDotL;
        vec3 ambient = u_AmbientLight * a_Color.rgb;
        v_Color = vec4(diffuse + ambient, a_Color.a);
    }
`</code></pre>
            <h3 class="title">点光源</h3>
            <p>点光源发出的光，在三维空间的不同位置上其方向也不同，在对点光源下的物体进行着色时，需要在每个入射点计算点光源的光在该处的方向。着色器需要知道点光源所在的位置，然后根据每个顶点的位置逐一计算。</p>
            <canvas ref="canvasRef4" v-show="!img4" class="webgl-canvas"></canvas>
            <img :src="img4" v-show="img4" class="webgl-canvas"/>
            <p>设置点光源的颜色和位置：</p>
            <pre><code>const lightPosition = [0.0, 3.0, 4.0]
const lightColor = [2.0, 2.0, 2.0] // 更强烈的白光</code></pre>
            <pre><code>// 顶点着色器
const VSHADER_SOURCE = `
    attribute vec4 a_Position;
    attribute vec4 a_Color;
    attribute vec4 a_Normal;
    uniform mat4 u_Matrix;
    uniform mat4 u_ModelMatrix; // 模型矩阵
    uniform mat4 u_NormalMatrix;
    uniform vec3 u_LightColor; // 光的颜色
    uniform vec3 u_LightPosition; // 光源位置
    uniform vec3 u_AmbientLight;
    varying vec4 v_Color;
    void main() {
        gl_Position = u_Matrix * a_Position;
        vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));
        vec4 vertexPosition = u_ModelMatrix * a_Position; // 计算顶点的世界坐标
        vec3 lightDirection = normalize(u_LightPosition - vec3(vertexPosition)); // 计算光线方向并归一化
        float nDotL = max(dot(lightDirection, normal), 0.0);
        vec3 diffuse = u_LightColor * vec3(a_Color) * nDotL;
        vec3 ambient = u_AmbientLight * a_Color.rgb;
        v_Color = vec4(diffuse + ambient, a_Color.a);
    }
`</code></pre>
            <p>逐片元渲染模式，可以使效果更加逼真：</p>
            <canvas ref="canvasRef5" v-show="!img5" class="webgl-canvas"></canvas>
            <img :src="img5" v-show="img5" class="webgl-canvas"/>
            <pre><code>const VSHADER_SOURCE = `
    attribute vec4 a_Position;
    attribute vec4 a_Color;
    attribute vec4 a_Normal;
    uniform mat4 u_Matrix;
    uniform mat4 u_ModelMatrix;
    uniform mat4 u_NormalMatrix;
    varying vec4 v_Color;
    varying vec3 v_Normal;
    varying vec3 v_Position;
    void main() {
        gl_Position = u_Matrix * a_Position;
        v_Position = vec3(u_ModelMatrix * a_Position);
        v_Normal = normalize(vec3(u_NormalMatrix * a_Normal));
        v_Color = a_Color;
    }
`
const FSHADER_SOURCE = `
    precision mediump float;
    uniform vec3 u_LightColor;
    uniform vec3 u_LightPosition;
    uniform vec3 u_AmbientLight;
    varying vec3 v_Normal;
    varying vec3 v_Position;
    varying vec4 v_Color;
    void main() {
        vec3 normal = normalize(v_Normal); // 对法线进行归一化
        vec3 lightDirection = normalize(u_LightPosition - v_Position);
        float nDotL = max(dot(lightDirection, normal),0.0);
        vec3 diffuse = u_LightColor * v_Color.rgb * nDotL;
        vec3 ambient = u_AmbientLight * v_Color.rgb;
        gl_FragColor = vec4(diffuse + ambient, v_Color.a);
    }
`</code></pre>
            <p>旋转的三维球体：</p>
            <canvas ref="canvasRef6" v-show="!img6" class="webgl-canvas"></canvas>
            <img :src="img6" v-show="img6" class="webgl-canvas"/>
        </div>
    </MyArticle>
</template>

<script>
import { onMounted, ref, onBeforeUnmount } from 'vue'
import Draw0 from './draw0'
import Draw1 from '../06/draw1'
import Draw2 from './draw2'
import Draw3 from './draw3'
import Draw4 from './draw4'
import Draw5 from './draw5'
import getSphereData from './sphere'
import { CuonMatrix4, Vector3 } from './cuonMatrix'

export default {
    setup () {
        const canvasRef0 = ref(null)
        const img0 = ref(null)
        const canvasRef1 = ref(null)
        const img1 = ref(null)
        const canvasRef2 = ref(null)
        const img2 = ref(null)
        const canvasRef3 = ref(null)
        const img3 = ref(null)
        let ani3 = null
        const canvasRef4 = ref(null)
        const img4 = ref(null)
        let ani4 = null
        const canvasRef5 = ref(null)
        const img5 = ref(null)
        let ani5 = null
        const canvasRef6 = ref(null)
        const img6 = ref(null)
        let ani6 = null
        onMounted(() => {
            // ------------------------------0.平行光的反射效果
            const currAngle0 = 0
            const viewMatrix0 = new CuonMatrix4()
            viewMatrix0.setLookAt(3, 3, 7, 0, 0, 0, 0, 1.0, 0)
            const modelMatrix0 = new CuonMatrix4()
            modelMatrix0.setRotate(currAngle0, 0, 0, 1)
            const modelViewMatrix0 = viewMatrix0.multiply(modelMatrix0)
            const projectMatrix0 = new CuonMatrix4()
            const size0 = window.getComputedStyle(canvasRef0.value, null)
            const ratio0 = parseInt(size0.width) / parseInt(size0.height)
            projectMatrix0.setPerspective(30, ratio0, 1, 100)
            const datas0 = new Float32Array([
                1.0, 1.0, 1.0, 0.4, 0.4, 1.0, 0.0, 0.0, 1.0, // front
                -1.0, 1.0, 1.0, 0.4, 0.4, 1.0, 0.0, 0.0, 1.0,
                -1.0, -1.0, 1.0, 0.4, 0.4, 1.0, 0.0, 0.0, 1.0,
                1.0, -1.0, 1.0, 0.4, 0.4, 1.0, 0.0, 0.0, 1.0,

                1.0, 1.0, 1.0, 0.4, 1.0, 0.4, 1.0, 0.0, 0.0, // right
                1.0, -1.0, 1.0, 0.4, 1.0, 0.4, 1.0, 0.0, 0.0,
                1.0, -1.0, -1.0, 0.4, 1.0, 0.4, 1.0, 0.0, 0.0,
                1.0, 1.0, -1.0, 0.4, 1.0, 0.4, 1.0, 0.0, 0.0,

                1.0, 1.0, 1.0, 1.0, 0.4, 0.4, 0.0, 1.0, 0.0, // up
                1.0, 1.0, -1.0, 1.0, 0.4, 0.4, 0.0, 1.0, 0.0,
                -1.0, 1.0, -1.0, 1.0, 0.4, 0.4, 0.0, 1.0, 0.0,
                -1.0, 1.0, 1.0, 1.0, 0.4, 0.4, 0.0, 1.0, 0.0,

                -1.0, 1.0, 1.0, 1.0, 1.0, 0.4, -1.0, 0.0, 0.0, // left
                -1.0, 1.0, -1.0, 1.0, 1.0, 0.4, -1.0, 0.0, 0.0,
                -1.0, -1.0, -1.0, 1.0, 1.0, 0.4, -1.0, 0.0, 0.0,
                -1.0, -1.0, 1.0, 1.0, 1.0, 0.4, -1.0, 0.0, 0.0,

                -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 0.0, -1.0, 0.0, // down
                1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 0.0, -1.0, 0.0,
                1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 0.0, -1.0, 0.0,
                -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 0.0, -1.0, 0.0,

                1.0, -1.0, -1.0, 0.4, 1.0, 1.0, 0.0, 0.0, -1.0, // back
                -1.0, -1.0, -1.0, 0.4, 1.0, 1.0, 0.0, 0.0, -1.0,
                -1.0, 1.0, -1.0, 0.4, 1.0, 1.0, 0.0, 0.0, -1.0,
                1.0, 1.0, -1.0, 0.4, 1.0, 1.0, 0.0, 0.0, -1.0
            ])
            const indices0 = new Uint8Array([
                0, 1, 2, 0, 2, 3,
                4, 5, 6, 4, 6, 7,
                8, 9, 10, 8, 10, 11,
                12, 13, 14, 12, 14, 15,
                16, 17, 18, 16, 18, 19,
                20, 21, 22, 20, 22, 23
            ])
            const lightColor0 = [1.0, 1.0, 1.0]
            const lightDirection = new Vector3([0.5, 3.0, 4.0])
            lightDirection.normalize()
            const matrix0 = projectMatrix0.multiply(modelViewMatrix0).elements
            const draw0 = new Draw0(canvasRef0.value, datas0, indices0, matrix0, lightColor0, lightDirection.elements)
            img0.value = draw0.img

            // -----------------------------1.无光照情况下
            const datas1 = new Float32Array([
                1.0, 1.0, 1.0, 0.4, 0.4, 1.0, // front
                -1.0, 1.0, 1.0, 0.4, 0.4, 1.0,
                -1.0, -1.0, 1.0, 0.4, 0.4, 1.0,
                1.0, -1.0, 1.0, 0.4, 0.4, 1.0,

                1.0, 1.0, 1.0, 0.4, 1.0, 0.4, // right
                1.0, -1.0, 1.0, 0.4, 1.0, 0.4,
                1.0, -1.0, -1.0, 0.4, 1.0, 0.4,
                1.0, 1.0, -1.0, 0.4, 1.0, 0.4,

                1.0, 1.0, 1.0, 1.0, 0.4, 0.4, // up
                1.0, 1.0, -1.0, 1.0, 0.4, 0.4,
                -1.0, 1.0, -1.0, 1.0, 0.4, 0.4,
                -1.0, 1.0, 1.0, 1.0, 0.4, 0.4,

                -1.0, 1.0, 1.0, 1.0, 1.0, 0.4, // left
                -1.0, 1.0, -1.0, 1.0, 1.0, 0.4,
                -1.0, -1.0, -1.0, 1.0, 1.0, 0.4,
                -1.0, -1.0, 1.0, 1.0, 1.0, 0.4,

                -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, // down
                1.0, -1.0, -1.0, 1.0, 1.0, 1.0,
                1.0, -1.0, 1.0, 1.0, 1.0, 1.0,
                -1.0, -1.0, 1.0, 1.0, 1.0, 1.0,

                1.0, -1.0, -1.0, 0.4, 1.0, 1.0, // back
                -1.0, -1.0, -1.0, 0.4, 1.0, 1.0,
                -1.0, 1.0, -1.0, 0.4, 1.0, 1.0,
                1.0, 1.0, -1.0, 0.4, 1.0, 1.0
            ])
            const draw1 = new Draw1(canvasRef1.value, datas1, indices0, matrix0)
            img1.value = draw1.img

            // ------------------------------2.平行光+环境光
            const ambientLight2 = [0.2, 0.2, 0.2]
            const draw2 = new Draw2(canvasRef2.value, datas0, indices0, matrix0, lightColor0, lightDirection.elements, ambientLight2)
            img2.value = draw2.img

            // -----------------------------3.平行光+环境光+旋转变换
            let currAngle3 = 0
            const rotateStep = 15.0 // 旋转速度
            let currTime3 = Date.now()
            let viewMatrix3 = new CuonMatrix4()
            viewMatrix3.setLookAt(3, 3, 7, 0, 0, 0, 0, 1.0, 0)
            const modelMatrix3 = new CuonMatrix4()
            modelMatrix3.setRotate(currAngle3, 0, 0, 1)
            let modelViewMatrix3 = viewMatrix3.multiply(modelMatrix3)
            let projectMatrix3 = new CuonMatrix4()
            const size3 = window.getComputedStyle(canvasRef3.value, null)
            const ratio3 = parseInt(size3.width) / parseInt(size3.height)
            projectMatrix3.setPerspective(30, ratio3, 1, 100)

            const normalMatrix3 = new CuonMatrix4()
            normalMatrix3.setInverseOf(modelMatrix3)
            normalMatrix3.transpose()
            const draw3 = new Draw3(canvasRef3.value, datas0, indices0, projectMatrix3.multiply(modelViewMatrix3).elements, lightColor0, lightDirection.elements, ambientLight2, normalMatrix3.elements)
            img3.value = draw3.img

            const ani3Update = () => {
                const now = Date.now()
                currAngle3 = (currAngle3 + (rotateStep * (now - currTime3)) / 1000) % 360
                currTime3 = now
                viewMatrix3 = new CuonMatrix4()
                viewMatrix3.setLookAt(3, 3, 7, 0, 0, 0, 0, 1.0, 0)
                modelMatrix3.setRotate(currAngle3, 0, 0, 1)
                modelViewMatrix3 = viewMatrix3.multiply(modelMatrix3)
                projectMatrix3 = new CuonMatrix4()
                projectMatrix3.setPerspective(30, ratio3, 1, 100)
                normalMatrix3.setInverseOf(modelMatrix3)
                normalMatrix3.transpose()
                draw3.redraw(projectMatrix3.multiply(modelViewMatrix3).elements, normalMatrix3.elements)
                img3.value = draw3.img
                ani3 = requestAnimationFrame(ani3Update)
            }
            ani3 = requestAnimationFrame(ani3Update)

            // -----------------------------4.点光源
            let currAngle4 = 0
            let currTime4 = Date.now()
            let viewMatrix4 = new CuonMatrix4()
            viewMatrix4.setLookAt(3, 3, 7, 0, 0, 0, 0, 1.0, 0)
            const modelMatrix4 = new CuonMatrix4()
            modelMatrix4.setRotate(currAngle4, 0, 0, 1)
            let modelViewMatrix4 = viewMatrix4.multiply(modelMatrix4)
            let projectMatrix4 = new CuonMatrix4()
            const size4 = window.getComputedStyle(canvasRef4.value, null)
            const ratio4 = parseInt(size4.width) / parseInt(size4.height)
            projectMatrix4.setPerspective(30, ratio4, 1, 100)
            const lightPosition = [0.0, 3.0, 4.0]
            const lightColor4 = [2.0, 2.0, 2.0]

            const normalMatrix4 = new CuonMatrix4()
            normalMatrix4.setInverseOf(modelMatrix4)
            normalMatrix4.transpose()
            const draw4 = new Draw4(canvasRef4.value, datas0, indices0, projectMatrix4.multiply(modelViewMatrix4).elements, lightColor4, lightPosition, ambientLight2, normalMatrix4.elements, modelMatrix4.elements)
            img4.value = draw4.img

            const ani4Update = () => {
                const now = Date.now()
                currAngle4 = (currAngle4 + (rotateStep * (now - currTime4)) / 1000) % 360
                currTime4 = now
                viewMatrix4 = new CuonMatrix4()
                viewMatrix4.setLookAt(3, 3, 7, 0, 0, 0, 0, 1.0, 0)
                modelMatrix4.setRotate(currAngle4, 0, 0, 1)
                modelViewMatrix4 = viewMatrix4.multiply(modelMatrix4)
                projectMatrix4 = new CuonMatrix4()
                projectMatrix4.setPerspective(30, ratio4, 1, 100)
                normalMatrix4.setInverseOf(modelMatrix4)
                normalMatrix4.transpose()
                draw4.redraw(projectMatrix4.multiply(modelViewMatrix4).elements, normalMatrix4.elements, modelMatrix4.elements)
                img4.value = draw4.img
                ani4 = requestAnimationFrame(ani4Update)
            }
            ani4 = requestAnimationFrame(ani4Update)

            // -----------------------------5.点光源 逐片元渲染模式
            let currAngle5 = 0
            let currTime5 = Date.now()
            let viewMatrix5 = new CuonMatrix4()
            viewMatrix5.setLookAt(3, 3, 7, 0, 0, 0, 0, 1.0, 0)
            const modelMatrix5 = new CuonMatrix4()
            modelMatrix5.setRotate(currAngle5, 0, 0, 1)
            let modelViewMatrix5 = viewMatrix5.multiply(modelMatrix5)
            let projectMatrix5 = new CuonMatrix4()
            const size5 = window.getComputedStyle(canvasRef5.value, null)
            const ratio5 = parseInt(size5.width) / parseInt(size5.height)
            projectMatrix5.setPerspective(30, ratio5, 1, 100)

            const normalMatrix5 = new CuonMatrix4()
            normalMatrix5.setInverseOf(modelMatrix5)
            normalMatrix5.transpose()
            const draw5 = new Draw4(canvasRef5.value, datas0, indices0, projectMatrix5.multiply(modelViewMatrix5).elements, lightColor4, lightPosition, ambientLight2, normalMatrix5.elements, modelMatrix5.elements, true)
            img5.value = draw5.img

            const ani5Update = () => {
                const now = Date.now()
                currAngle5 = (currAngle5 + (rotateStep * (now - currTime5)) / 1000) % 360
                currTime5 = now
                viewMatrix5 = new CuonMatrix4()
                viewMatrix5.setLookAt(3, 3, 7, 0, 0, 0, 0, 1.0, 0)
                modelMatrix5.setRotate(currAngle5, 0, 0, 1)
                modelViewMatrix5 = viewMatrix5.multiply(modelMatrix5)
                projectMatrix5 = new CuonMatrix4()
                projectMatrix5.setPerspective(30, ratio5, 1, 100)
                normalMatrix5.setInverseOf(modelMatrix5)
                normalMatrix5.transpose()
                draw5.redraw(projectMatrix5.multiply(modelViewMatrix5).elements, normalMatrix5.elements, modelMatrix5.elements)
                img5.value = draw5.img
                ani5 = requestAnimationFrame(ani5Update)
            }
            ani5 = requestAnimationFrame(ani5Update)

            // -----------------------------6.三维球体
            let { positions: sphereData, indices: sphereIndices } = getSphereData(25)
            console.log('sphereData...', sphereData, sphereIndices)
            sphereData = new Float32Array(sphereData)
            sphereIndices = new Uint16Array(sphereIndices)
            let currAngle6 = 0
            let currTime6 = Date.now()
            let viewMatrix6 = new CuonMatrix4()
            viewMatrix6.setLookAt(0, 0, 6, 0, 0, 0, 0, 1, 0)
            const modelMatrix6 = new CuonMatrix4()
            modelMatrix6.setRotate(currAngle6, 0, 1, 0)
            let modelViewMatrix6 = viewMatrix6.multiply(modelMatrix6)
            let projectMatrix6 = new CuonMatrix4()
            const size6 = window.getComputedStyle(canvasRef6.value, null)
            const ratio6 = parseInt(size6.width) / parseInt(size6.height)
            projectMatrix6.setPerspective(30, ratio6, 1, 100)

            const normalMatrix6 = new CuonMatrix4()
            normalMatrix6.setInverseOf(modelMatrix6)
            normalMatrix6.transpose()
            const lightColor6 = [0.8, 0.8, 0.8]
            const ambientLight6 = [0.2, 0.2, 0.2]
            const lightPosition6 = [5.0, 8.0, 7.0]
            const draw6 = new Draw5(canvasRef6.value, sphereData, sphereIndices, sphereData, [1.0, 1.0, 1.0], projectMatrix6.multiply(modelViewMatrix6).elements, lightColor6, lightPosition6, ambientLight6, normalMatrix6.elements, modelMatrix6.elements, true, 1)
            img6.value = draw6.img
            const rotateStep6 = 25

            const ani6Update = () => {
                const now = Date.now()
                currAngle6 = (currAngle6 + (rotateStep6 * (now - currTime6)) / 1000) % 360
                currTime6 = now
                viewMatrix6 = new CuonMatrix4()
                viewMatrix6.setLookAt(0, 0, 6, 0, 0, 0, 0, 1, 0)
                modelMatrix6.setRotate(currAngle6, 0, 1, 0)
                modelViewMatrix6 = viewMatrix6.multiply(modelMatrix6)
                projectMatrix6 = new CuonMatrix4()
                projectMatrix6.setPerspective(30, ratio6, 1, 100)
                normalMatrix6.setInverseOf(modelMatrix6)
                normalMatrix6.transpose()
                draw6.redraw(projectMatrix6.multiply(modelViewMatrix6).elements, normalMatrix6.elements, modelMatrix6.elements, 1)
                img6.value = draw6.img
                ani6 = requestAnimationFrame(ani6Update)
            }
            ani6 = requestAnimationFrame(ani6Update)
        })

        onBeforeUnmount(() => {
            if (ani3) {
                cancelAnimationFrame(ani3)
            }
            if (ani4) {
                cancelAnimationFrame(ani4)
            }
            if (ani5) {
                cancelAnimationFrame(ani5)
            }
            if (ani6) {
                cancelAnimationFrame(ani6)
            }
        })
        return {
            canvasRef0,
            img0,
            canvasRef1,
            img1,
            canvasRef2,
            img2,
            canvasRef3,
            img3,
            canvasRef4,
            img4,
            canvasRef5,
            img5,
            canvasRef6,
            img6
        }
    }
}
</script>

<style lang="scss">
    @use "./style.scss";
</style>
